{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import scipy.spatial.distance as ssd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 读取训练集，并把数据规范化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        1        1       5\n",
       "1        1        2       3\n",
       "2        1        3       4\n",
       "3        1        4       3\n",
       "4        1        5       3"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 读取训练集\n",
    "df_training_data = pd.read_csv(\n",
    "    './data/movielen_rating_training.base',\n",
    "    sep='\\t',\n",
    "    names=['user_id','item_id','rating'],\n",
    "    usecols=[0,1,2],\n",
    ")\n",
    "df_training_data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 进行查看数据，看是否有缺失"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 80000 entries, 0 to 79999\n",
      "Data columns (total 3 columns):\n",
      "user_id    80000 non-null int64\n",
      "item_id    80000 non-null int64\n",
      "rating     80000 non-null int64\n",
      "dtypes: int64(3)\n",
      "memory usage: 1.8 MB\n"
     ]
    }
   ],
   "source": [
    "df_training_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 所有不重复的用户与商品的id\n",
    "user_ids = df_training_data['user_id'].unique()\n",
    "item_ids = df_training_data['item_id'].unique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "用户数 943\n",
      "商品数 1650\n"
     ]
    }
   ],
   "source": [
    "# 用户和商品的数量\n",
    "user_quantity = len(user_ids)\n",
    "item_quantity = len(item_ids)\n",
    "print('用户数',user_quantity)\n",
    "print('商品数',item_quantity)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对id与index进行转换，方便后面数据处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 构造出id与index的对应关系\n",
    "user_id_to_index_dict = {}\n",
    "user_index_to_id_dict = {}\n",
    "item_id_to_index_dict = {}\n",
    "item_index_to_id_dict = {}\n",
    "\n",
    "for user_index,user_id in enumerate(user_ids):\n",
    "    user_id_to_index_dict[user_id] = user_index\n",
    "    user_index_to_id_dict[user_index] = user_id\n",
    "\n",
    "for item_index,item_id in enumerate(item_ids):\n",
    "    item_id_to_index_dict[item_id] = item_index\n",
    "    item_index_to_id_dict[item_index] = item_id"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通过apply与lambda将原来训练集中的id变更index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 把训练集Dataframe中的id变更为index\n",
    "df_training_data['user_id'] = df_training_data['user_id'].apply(\n",
    "    lambda user_id : user_id_to_index_dict[user_id]\n",
    ")\n",
    "\n",
    "df_training_data['item_id'] = df_training_data['item_id'].apply(\n",
    "    lambda item_id : item_id_to_index_dict[item_id]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 0,\n",
       " 2: 1,\n",
       " 3: 2,\n",
       " 4: 3,\n",
       " 5: 4,\n",
       " 6: 5,\n",
       " 7: 6,\n",
       " 8: 7,\n",
       " 9: 8,\n",
       " 10: 9,\n",
       " 11: 10,\n",
       " 12: 11,\n",
       " 13: 12,\n",
       " 14: 13,\n",
       " 15: 14,\n",
       " 16: 15,\n",
       " 17: 16,\n",
       " 18: 17,\n",
       " 19: 18,\n",
       " 20: 19,\n",
       " 21: 20,\n",
       " 22: 21,\n",
       " 23: 22,\n",
       " 24: 23,\n",
       " 25: 24,\n",
       " 26: 25,\n",
       " 27: 26,\n",
       " 28: 27,\n",
       " 29: 28,\n",
       " 30: 29,\n",
       " 31: 30,\n",
       " 32: 31,\n",
       " 33: 32,\n",
       " 34: 33,\n",
       " 35: 34,\n",
       " 36: 35,\n",
       " 37: 36,\n",
       " 38: 37,\n",
       " 39: 38,\n",
       " 40: 39,\n",
       " 41: 40,\n",
       " 42: 41,\n",
       " 43: 42,\n",
       " 44: 43,\n",
       " 45: 44,\n",
       " 46: 45,\n",
       " 47: 46,\n",
       " 48: 47,\n",
       " 49: 48,\n",
       " 50: 49,\n",
       " 51: 50,\n",
       " 52: 51,\n",
       " 53: 52,\n",
       " 54: 53,\n",
       " 55: 54,\n",
       " 56: 55,\n",
       " 57: 56,\n",
       " 58: 57,\n",
       " 59: 58,\n",
       " 60: 59,\n",
       " 61: 60,\n",
       " 62: 61,\n",
       " 63: 62,\n",
       " 64: 63,\n",
       " 65: 64,\n",
       " 66: 65,\n",
       " 67: 66,\n",
       " 68: 67,\n",
       " 69: 68,\n",
       " 70: 69,\n",
       " 71: 70,\n",
       " 72: 71,\n",
       " 73: 72,\n",
       " 74: 73,\n",
       " 75: 74,\n",
       " 76: 75,\n",
       " 77: 76,\n",
       " 78: 77,\n",
       " 79: 78,\n",
       " 80: 79,\n",
       " 81: 80,\n",
       " 82: 81,\n",
       " 83: 82,\n",
       " 84: 83,\n",
       " 85: 84,\n",
       " 86: 85,\n",
       " 87: 86,\n",
       " 88: 87,\n",
       " 89: 88,\n",
       " 90: 89,\n",
       " 91: 90,\n",
       " 92: 91,\n",
       " 93: 92,\n",
       " 94: 93,\n",
       " 95: 94,\n",
       " 96: 95,\n",
       " 97: 96,\n",
       " 98: 97,\n",
       " 99: 98,\n",
       " 100: 99,\n",
       " 101: 100,\n",
       " 102: 101,\n",
       " 103: 102,\n",
       " 104: 103,\n",
       " 105: 104,\n",
       " 106: 105,\n",
       " 107: 106,\n",
       " 108: 107,\n",
       " 109: 108,\n",
       " 110: 109,\n",
       " 111: 110,\n",
       " 112: 111,\n",
       " 113: 112,\n",
       " 114: 113,\n",
       " 115: 114,\n",
       " 116: 115,\n",
       " 117: 116,\n",
       " 118: 117,\n",
       " 119: 118,\n",
       " 120: 119,\n",
       " 121: 120,\n",
       " 122: 121,\n",
       " 123: 122,\n",
       " 124: 123,\n",
       " 125: 124,\n",
       " 126: 125,\n",
       " 127: 126,\n",
       " 128: 127,\n",
       " 129: 128,\n",
       " 130: 129,\n",
       " 131: 130,\n",
       " 132: 131,\n",
       " 133: 132,\n",
       " 134: 133,\n",
       " 135: 134,\n",
       " 136: 135,\n",
       " 137: 136,\n",
       " 138: 137,\n",
       " 139: 138,\n",
       " 140: 139,\n",
       " 141: 140,\n",
       " 142: 141,\n",
       " 143: 142,\n",
       " 144: 143,\n",
       " 145: 144,\n",
       " 146: 145,\n",
       " 147: 146,\n",
       " 148: 147,\n",
       " 149: 148,\n",
       " 150: 149,\n",
       " 151: 150,\n",
       " 152: 151,\n",
       " 153: 152,\n",
       " 154: 153,\n",
       " 155: 154,\n",
       " 156: 155,\n",
       " 157: 156,\n",
       " 158: 157,\n",
       " 159: 158,\n",
       " 160: 159,\n",
       " 161: 160,\n",
       " 162: 161,\n",
       " 163: 162,\n",
       " 164: 163,\n",
       " 165: 164,\n",
       " 166: 165,\n",
       " 167: 166,\n",
       " 168: 167,\n",
       " 169: 168,\n",
       " 170: 169,\n",
       " 171: 170,\n",
       " 172: 171,\n",
       " 173: 172,\n",
       " 174: 173,\n",
       " 175: 174,\n",
       " 176: 175,\n",
       " 177: 176,\n",
       " 178: 177,\n",
       " 179: 178,\n",
       " 180: 179,\n",
       " 181: 180,\n",
       " 182: 181,\n",
       " 183: 182,\n",
       " 184: 183,\n",
       " 185: 184,\n",
       " 186: 185,\n",
       " 187: 186,\n",
       " 188: 187,\n",
       " 189: 188,\n",
       " 190: 189,\n",
       " 191: 190,\n",
       " 192: 191,\n",
       " 193: 192,\n",
       " 194: 193,\n",
       " 195: 194,\n",
       " 196: 195,\n",
       " 197: 196,\n",
       " 198: 197,\n",
       " 199: 198,\n",
       " 200: 199,\n",
       " 201: 200,\n",
       " 202: 201,\n",
       " 203: 202,\n",
       " 204: 203,\n",
       " 205: 204,\n",
       " 206: 205,\n",
       " 207: 206,\n",
       " 208: 207,\n",
       " 209: 208,\n",
       " 210: 209,\n",
       " 211: 210,\n",
       " 212: 211,\n",
       " 213: 212,\n",
       " 214: 213,\n",
       " 215: 214,\n",
       " 216: 215,\n",
       " 217: 216,\n",
       " 218: 217,\n",
       " 219: 218,\n",
       " 220: 219,\n",
       " 221: 220,\n",
       " 222: 221,\n",
       " 223: 222,\n",
       " 224: 223,\n",
       " 225: 224,\n",
       " 226: 225,\n",
       " 227: 226,\n",
       " 228: 227,\n",
       " 229: 228,\n",
       " 230: 229,\n",
       " 231: 230,\n",
       " 232: 231,\n",
       " 233: 232,\n",
       " 234: 233,\n",
       " 235: 234,\n",
       " 236: 235,\n",
       " 237: 236,\n",
       " 238: 237,\n",
       " 239: 238,\n",
       " 240: 239,\n",
       " 241: 240,\n",
       " 242: 241,\n",
       " 243: 242,\n",
       " 244: 243,\n",
       " 245: 244,\n",
       " 246: 245,\n",
       " 247: 246,\n",
       " 248: 247,\n",
       " 249: 248,\n",
       " 250: 249,\n",
       " 251: 250,\n",
       " 252: 251,\n",
       " 253: 252,\n",
       " 254: 253,\n",
       " 255: 254,\n",
       " 256: 255,\n",
       " 257: 256,\n",
       " 258: 257,\n",
       " 259: 258,\n",
       " 260: 259,\n",
       " 261: 260,\n",
       " 262: 261,\n",
       " 263: 262,\n",
       " 264: 263,\n",
       " 265: 264,\n",
       " 266: 265,\n",
       " 267: 266,\n",
       " 268: 267,\n",
       " 269: 268,\n",
       " 270: 269,\n",
       " 271: 270,\n",
       " 272: 271,\n",
       " 273: 272,\n",
       " 274: 273,\n",
       " 275: 274,\n",
       " 276: 275,\n",
       " 277: 276,\n",
       " 278: 277,\n",
       " 279: 278,\n",
       " 280: 279,\n",
       " 281: 280,\n",
       " 282: 281,\n",
       " 283: 282,\n",
       " 284: 283,\n",
       " 285: 284,\n",
       " 286: 285,\n",
       " 287: 286,\n",
       " 288: 287,\n",
       " 289: 288,\n",
       " 290: 289,\n",
       " 291: 290,\n",
       " 292: 291,\n",
       " 293: 292,\n",
       " 294: 293,\n",
       " 295: 294,\n",
       " 296: 295,\n",
       " 297: 296,\n",
       " 298: 297,\n",
       " 299: 298,\n",
       " 300: 299,\n",
       " 301: 300,\n",
       " 302: 301,\n",
       " 303: 302,\n",
       " 304: 303,\n",
       " 305: 304,\n",
       " 306: 305,\n",
       " 307: 306,\n",
       " 308: 307,\n",
       " 309: 308,\n",
       " 310: 309,\n",
       " 311: 310,\n",
       " 312: 311,\n",
       " 313: 312,\n",
       " 314: 313,\n",
       " 315: 314,\n",
       " 316: 315,\n",
       " 317: 316,\n",
       " 318: 317,\n",
       " 319: 318,\n",
       " 320: 319,\n",
       " 321: 320,\n",
       " 322: 321,\n",
       " 323: 322,\n",
       " 324: 323,\n",
       " 325: 324,\n",
       " 326: 325,\n",
       " 327: 326,\n",
       " 328: 327,\n",
       " 329: 328,\n",
       " 330: 329,\n",
       " 331: 330,\n",
       " 332: 331,\n",
       " 333: 332,\n",
       " 334: 333,\n",
       " 335: 334,\n",
       " 336: 335,\n",
       " 337: 336,\n",
       " 338: 337,\n",
       " 339: 338,\n",
       " 340: 339,\n",
       " 341: 340,\n",
       " 342: 341,\n",
       " 343: 342,\n",
       " 344: 343,\n",
       " 345: 344,\n",
       " 346: 345,\n",
       " 347: 346,\n",
       " 348: 347,\n",
       " 349: 348,\n",
       " 350: 349,\n",
       " 351: 350,\n",
       " 352: 351,\n",
       " 353: 352,\n",
       " 354: 353,\n",
       " 355: 354,\n",
       " 356: 355,\n",
       " 357: 356,\n",
       " 358: 357,\n",
       " 359: 358,\n",
       " 360: 359,\n",
       " 361: 360,\n",
       " 362: 361,\n",
       " 363: 362,\n",
       " 364: 363,\n",
       " 365: 364,\n",
       " 366: 365,\n",
       " 367: 366,\n",
       " 368: 367,\n",
       " 369: 368,\n",
       " 370: 369,\n",
       " 371: 370,\n",
       " 372: 371,\n",
       " 373: 372,\n",
       " 374: 373,\n",
       " 375: 374,\n",
       " 376: 375,\n",
       " 377: 376,\n",
       " 378: 377,\n",
       " 379: 378,\n",
       " 380: 379,\n",
       " 381: 380,\n",
       " 382: 381,\n",
       " 383: 382,\n",
       " 384: 383,\n",
       " 385: 384,\n",
       " 386: 385,\n",
       " 387: 386,\n",
       " 388: 387,\n",
       " 389: 388,\n",
       " 390: 389,\n",
       " 391: 390,\n",
       " 392: 391,\n",
       " 393: 392,\n",
       " 394: 393,\n",
       " 395: 394,\n",
       " 396: 395,\n",
       " 397: 396,\n",
       " 398: 397,\n",
       " 399: 398,\n",
       " 400: 399,\n",
       " 401: 400,\n",
       " 402: 401,\n",
       " 403: 402,\n",
       " 404: 403,\n",
       " 405: 404,\n",
       " 406: 405,\n",
       " 407: 406,\n",
       " 408: 407,\n",
       " 409: 408,\n",
       " 410: 409,\n",
       " 411: 410,\n",
       " 412: 411,\n",
       " 413: 412,\n",
       " 414: 413,\n",
       " 415: 414,\n",
       " 416: 415,\n",
       " 417: 416,\n",
       " 418: 417,\n",
       " 419: 418,\n",
       " 420: 419,\n",
       " 421: 420,\n",
       " 422: 421,\n",
       " 423: 422,\n",
       " 424: 423,\n",
       " 425: 424,\n",
       " 426: 425,\n",
       " 427: 426,\n",
       " 428: 427,\n",
       " 429: 428,\n",
       " 430: 429,\n",
       " 431: 430,\n",
       " 432: 431,\n",
       " 433: 432,\n",
       " 434: 433,\n",
       " 435: 434,\n",
       " 436: 435,\n",
       " 437: 436,\n",
       " 438: 437,\n",
       " 439: 438,\n",
       " 440: 439,\n",
       " 441: 440,\n",
       " 442: 441,\n",
       " 443: 442,\n",
       " 444: 443,\n",
       " 445: 444,\n",
       " 446: 445,\n",
       " 447: 446,\n",
       " 448: 447,\n",
       " 449: 448,\n",
       " 450: 449,\n",
       " 451: 450,\n",
       " 452: 451,\n",
       " 453: 452,\n",
       " 454: 453,\n",
       " 455: 454,\n",
       " 456: 455,\n",
       " 457: 456,\n",
       " 458: 457,\n",
       " 459: 458,\n",
       " 460: 459,\n",
       " 461: 460,\n",
       " 462: 461,\n",
       " 463: 462,\n",
       " 464: 463,\n",
       " 465: 464,\n",
       " 466: 465,\n",
       " 467: 466,\n",
       " 468: 467,\n",
       " 469: 468,\n",
       " 470: 469,\n",
       " 471: 470,\n",
       " 472: 471,\n",
       " 473: 472,\n",
       " 474: 473,\n",
       " 475: 474,\n",
       " 476: 475,\n",
       " 477: 476,\n",
       " 478: 477,\n",
       " 479: 478,\n",
       " 480: 479,\n",
       " 481: 480,\n",
       " 482: 481,\n",
       " 483: 482,\n",
       " 484: 483,\n",
       " 485: 484,\n",
       " 486: 485,\n",
       " 487: 486,\n",
       " 488: 487,\n",
       " 489: 488,\n",
       " 490: 489,\n",
       " 491: 490,\n",
       " 492: 491,\n",
       " 493: 492,\n",
       " 494: 493,\n",
       " 495: 494,\n",
       " 496: 495,\n",
       " 497: 496,\n",
       " 498: 497,\n",
       " 499: 498,\n",
       " 500: 499,\n",
       " 501: 500,\n",
       " 502: 501,\n",
       " 503: 502,\n",
       " 504: 503,\n",
       " 505: 504,\n",
       " 506: 505,\n",
       " 507: 506,\n",
       " 508: 507,\n",
       " 509: 508,\n",
       " 510: 509,\n",
       " 511: 510,\n",
       " 512: 511,\n",
       " 513: 512,\n",
       " 514: 513,\n",
       " 515: 514,\n",
       " 516: 515,\n",
       " 517: 516,\n",
       " 518: 517,\n",
       " 519: 518,\n",
       " 520: 519,\n",
       " 521: 520,\n",
       " 522: 521,\n",
       " 523: 522,\n",
       " 524: 523,\n",
       " 525: 524,\n",
       " 526: 525,\n",
       " 527: 526,\n",
       " 528: 527,\n",
       " 529: 528,\n",
       " 530: 529,\n",
       " 531: 530,\n",
       " 532: 531,\n",
       " 533: 532,\n",
       " 534: 533,\n",
       " 535: 534,\n",
       " 536: 535,\n",
       " 537: 536,\n",
       " 538: 537,\n",
       " 539: 538,\n",
       " 540: 539,\n",
       " 541: 540,\n",
       " 542: 541,\n",
       " 543: 542,\n",
       " 544: 543,\n",
       " 545: 544,\n",
       " 546: 545,\n",
       " 547: 546,\n",
       " 548: 547,\n",
       " 549: 548,\n",
       " 550: 549,\n",
       " 551: 550,\n",
       " 552: 551,\n",
       " 553: 552,\n",
       " 554: 553,\n",
       " 555: 554,\n",
       " 556: 555,\n",
       " 557: 556,\n",
       " 558: 557,\n",
       " 559: 558,\n",
       " 560: 559,\n",
       " 561: 560,\n",
       " 562: 561,\n",
       " 563: 562,\n",
       " 564: 563,\n",
       " 565: 564,\n",
       " 566: 565,\n",
       " 567: 566,\n",
       " 568: 567,\n",
       " 569: 568,\n",
       " 570: 569,\n",
       " 571: 570,\n",
       " 572: 571,\n",
       " 573: 572,\n",
       " 574: 573,\n",
       " 575: 574,\n",
       " 576: 575,\n",
       " 577: 576,\n",
       " 578: 577,\n",
       " 579: 578,\n",
       " 580: 579,\n",
       " 581: 580,\n",
       " 582: 581,\n",
       " 583: 582,\n",
       " 584: 583,\n",
       " 585: 584,\n",
       " 586: 585,\n",
       " 587: 586,\n",
       " 588: 587,\n",
       " 589: 588,\n",
       " 590: 589,\n",
       " 591: 590,\n",
       " 592: 591,\n",
       " 593: 592,\n",
       " 594: 593,\n",
       " 595: 594,\n",
       " 596: 595,\n",
       " 597: 596,\n",
       " 598: 597,\n",
       " 599: 598,\n",
       " 600: 599,\n",
       " 601: 600,\n",
       " 602: 601,\n",
       " 603: 602,\n",
       " 604: 603,\n",
       " 605: 604,\n",
       " 606: 605,\n",
       " 607: 606,\n",
       " 608: 607,\n",
       " 609: 608,\n",
       " 610: 609,\n",
       " 611: 610,\n",
       " 612: 611,\n",
       " 613: 612,\n",
       " 614: 613,\n",
       " 615: 614,\n",
       " 616: 615,\n",
       " 617: 616,\n",
       " 618: 617,\n",
       " 619: 618,\n",
       " 620: 619,\n",
       " 621: 620,\n",
       " 622: 621,\n",
       " 623: 622,\n",
       " 624: 623,\n",
       " 625: 624,\n",
       " 626: 625,\n",
       " 627: 626,\n",
       " 628: 627,\n",
       " 629: 628,\n",
       " 630: 629,\n",
       " 631: 630,\n",
       " 632: 631,\n",
       " 633: 632,\n",
       " 634: 633,\n",
       " 635: 634,\n",
       " 636: 635,\n",
       " 637: 636,\n",
       " 638: 637,\n",
       " 639: 638,\n",
       " 640: 639,\n",
       " 641: 640,\n",
       " 642: 641,\n",
       " 643: 642,\n",
       " 644: 643,\n",
       " 645: 644,\n",
       " 646: 645,\n",
       " 647: 646,\n",
       " 648: 647,\n",
       " 649: 648,\n",
       " 650: 649,\n",
       " 651: 650,\n",
       " 652: 651,\n",
       " 653: 652,\n",
       " 654: 653,\n",
       " 655: 654,\n",
       " 656: 655,\n",
       " 657: 656,\n",
       " 658: 657,\n",
       " 659: 658,\n",
       " 660: 659,\n",
       " 661: 660,\n",
       " 662: 661,\n",
       " 663: 662,\n",
       " 664: 663,\n",
       " 665: 664,\n",
       " 666: 665,\n",
       " 667: 666,\n",
       " 668: 667,\n",
       " 669: 668,\n",
       " 670: 669,\n",
       " 671: 670,\n",
       " 672: 671,\n",
       " 673: 672,\n",
       " 674: 673,\n",
       " 675: 674,\n",
       " 676: 675,\n",
       " 677: 676,\n",
       " 678: 677,\n",
       " 679: 678,\n",
       " 680: 679,\n",
       " 681: 680,\n",
       " 682: 681,\n",
       " 683: 682,\n",
       " 684: 683,\n",
       " 685: 684,\n",
       " 686: 685,\n",
       " 687: 686,\n",
       " 688: 687,\n",
       " 689: 688,\n",
       " 690: 689,\n",
       " 691: 690,\n",
       " 692: 691,\n",
       " 693: 692,\n",
       " 694: 693,\n",
       " 695: 694,\n",
       " 696: 695,\n",
       " 697: 696,\n",
       " 698: 697,\n",
       " 699: 698,\n",
       " 700: 699,\n",
       " 701: 700,\n",
       " 702: 701,\n",
       " 703: 702,\n",
       " 704: 703,\n",
       " 705: 704,\n",
       " 706: 705,\n",
       " 707: 706,\n",
       " 708: 707,\n",
       " 709: 708,\n",
       " 710: 709,\n",
       " 711: 710,\n",
       " 712: 711,\n",
       " 713: 712,\n",
       " 714: 713,\n",
       " 715: 714,\n",
       " 716: 715,\n",
       " 717: 716,\n",
       " 718: 717,\n",
       " 719: 718,\n",
       " 720: 719,\n",
       " 721: 720,\n",
       " 722: 721,\n",
       " 723: 722,\n",
       " 724: 723,\n",
       " 725: 724,\n",
       " 726: 725,\n",
       " 727: 726,\n",
       " 728: 727,\n",
       " 729: 728,\n",
       " 730: 729,\n",
       " 731: 730,\n",
       " 732: 731,\n",
       " 733: 732,\n",
       " 734: 733,\n",
       " 735: 734,\n",
       " 736: 735,\n",
       " 737: 736,\n",
       " 738: 737,\n",
       " 739: 738,\n",
       " 740: 739,\n",
       " 741: 740,\n",
       " 742: 741,\n",
       " 743: 742,\n",
       " 744: 743,\n",
       " 745: 744,\n",
       " 746: 745,\n",
       " 747: 746,\n",
       " 748: 747,\n",
       " 749: 748,\n",
       " 750: 749,\n",
       " 751: 750,\n",
       " 752: 751,\n",
       " 753: 752,\n",
       " 754: 753,\n",
       " 755: 754,\n",
       " 756: 755,\n",
       " 757: 756,\n",
       " 758: 757,\n",
       " 759: 758,\n",
       " 760: 759,\n",
       " 761: 760,\n",
       " 762: 761,\n",
       " 763: 762,\n",
       " 764: 763,\n",
       " 765: 764,\n",
       " 766: 765,\n",
       " 767: 766,\n",
       " 768: 767,\n",
       " 769: 768,\n",
       " 770: 769,\n",
       " 771: 770,\n",
       " 772: 771,\n",
       " 773: 772,\n",
       " 774: 773,\n",
       " 775: 774,\n",
       " 776: 775,\n",
       " 777: 776,\n",
       " 778: 777,\n",
       " 779: 778,\n",
       " 780: 779,\n",
       " 781: 780,\n",
       " 782: 781,\n",
       " 783: 782,\n",
       " 784: 783,\n",
       " 785: 784,\n",
       " 786: 785,\n",
       " 787: 786,\n",
       " 788: 787,\n",
       " 789: 788,\n",
       " 790: 789,\n",
       " 791: 790,\n",
       " 792: 791,\n",
       " 793: 792,\n",
       " 794: 793,\n",
       " 795: 794,\n",
       " 796: 795,\n",
       " 797: 796,\n",
       " 798: 797,\n",
       " 799: 798,\n",
       " 800: 799,\n",
       " 801: 800,\n",
       " 802: 801,\n",
       " 803: 802,\n",
       " 804: 803,\n",
       " 805: 804,\n",
       " 806: 805,\n",
       " 807: 806,\n",
       " 808: 807,\n",
       " 809: 808,\n",
       " 810: 809,\n",
       " 811: 810,\n",
       " 812: 811,\n",
       " 813: 812,\n",
       " 814: 813,\n",
       " 815: 814,\n",
       " 816: 815,\n",
       " 817: 816,\n",
       " 818: 817,\n",
       " 819: 818,\n",
       " 820: 819,\n",
       " 821: 820,\n",
       " 822: 821,\n",
       " 823: 822,\n",
       " 824: 823,\n",
       " 825: 824,\n",
       " 826: 825,\n",
       " 827: 826,\n",
       " 828: 827,\n",
       " 829: 828,\n",
       " 830: 829,\n",
       " 831: 830,\n",
       " 832: 831,\n",
       " 833: 832,\n",
       " 834: 833,\n",
       " 835: 834,\n",
       " 836: 835,\n",
       " 837: 836,\n",
       " 838: 837,\n",
       " 839: 838,\n",
       " 840: 839,\n",
       " 841: 840,\n",
       " 842: 841,\n",
       " 843: 842,\n",
       " 844: 843,\n",
       " 845: 844,\n",
       " 846: 845,\n",
       " 847: 846,\n",
       " 848: 847,\n",
       " 849: 848,\n",
       " 850: 849,\n",
       " 851: 850,\n",
       " 852: 851,\n",
       " 853: 852,\n",
       " 854: 853,\n",
       " 855: 854,\n",
       " 856: 855,\n",
       " 857: 856,\n",
       " 858: 857,\n",
       " 859: 858,\n",
       " 860: 859,\n",
       " 861: 860,\n",
       " 862: 861,\n",
       " 863: 862,\n",
       " 864: 863,\n",
       " 865: 864,\n",
       " 866: 865,\n",
       " 867: 866,\n",
       " 868: 867,\n",
       " 869: 868,\n",
       " 870: 869,\n",
       " 871: 870,\n",
       " 872: 871,\n",
       " 873: 872,\n",
       " 874: 873,\n",
       " 875: 874,\n",
       " 876: 875,\n",
       " 877: 876,\n",
       " 878: 877,\n",
       " 879: 878,\n",
       " 880: 879,\n",
       " 881: 880,\n",
       " 882: 881,\n",
       " 883: 882,\n",
       " 884: 883,\n",
       " 885: 884,\n",
       " 886: 885,\n",
       " 887: 886,\n",
       " 888: 887,\n",
       " 889: 888,\n",
       " 890: 889,\n",
       " 891: 890,\n",
       " 892: 891,\n",
       " 893: 892,\n",
       " 894: 893,\n",
       " 895: 894,\n",
       " 896: 895,\n",
       " 897: 896,\n",
       " 898: 897,\n",
       " 899: 898,\n",
       " 900: 899,\n",
       " 901: 900,\n",
       " 902: 901,\n",
       " 903: 902,\n",
       " 904: 903,\n",
       " 905: 904,\n",
       " 906: 905,\n",
       " 907: 906,\n",
       " 908: 907,\n",
       " 909: 908,\n",
       " 910: 909,\n",
       " 911: 910,\n",
       " 912: 911,\n",
       " 913: 912,\n",
       " 914: 913,\n",
       " 915: 914,\n",
       " 916: 915,\n",
       " 917: 916,\n",
       " 918: 917,\n",
       " 919: 918,\n",
       " 920: 919,\n",
       " 921: 920,\n",
       " 922: 921,\n",
       " 923: 922,\n",
       " 924: 923,\n",
       " 925: 924,\n",
       " 926: 925,\n",
       " 927: 926,\n",
       " 928: 927,\n",
       " 929: 928,\n",
       " 930: 929,\n",
       " 931: 930,\n",
       " 932: 931,\n",
       " 933: 932,\n",
       " 934: 933,\n",
       " 935: 934,\n",
       " 936: 935,\n",
       " 937: 936,\n",
       " 938: 937,\n",
       " 939: 938,\n",
       " 940: 939,\n",
       " 941: 940,\n",
       " 942: 941,\n",
       " 943: 942}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_id_to_index_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        0        0       5\n",
       "1        0        1       3\n",
       "2        0        2       4\n",
       "3        0        3       3\n",
       "4        0        4       3"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_training_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_index</th>\n",
       "      <th>item_index</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_index  item_index  rating\n",
       "0           0           0       5\n",
       "1           0           1       3\n",
       "2           0           2       4\n",
       "3           0           3       3\n",
       "4           0           4       3"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变更Dataframe中的列名\n",
    "df_training_data.columns = ['user_index','item_index','rating']\n",
    "df_training_data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 建立打分与相似度矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 一般需要初始化矩阵，方便后面数据处理的速度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       ...,\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.]])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 初始化打分矩阵\n",
    "user_item_rating_array = np.zeros(\n",
    "    shape=(user_quantity,item_quantity),\n",
    ")\n",
    "user_item_rating_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 填充打分矩阵\n",
    "#  对用户index进行分组\n",
    "for user_index,groupby_userindex in df_training_data.groupby('user_index'):\n",
    "    # 用户对各个商品的打分均值\n",
    "    items_rating = groupby_userindex.groupby('item_index')['rating'].mean()\n",
    "    # 进行打分矩阵的数据填充\n",
    "    for item_index in items_rating.index:\n",
    "        user_item_rating_array[user_index,item_index] = items_rating[item_index]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通过groupby进行分组，先取出第一个user_index的所有评分集合，再对不同的item_index进行分组，有相同的进行取平均值（平均值不一定好，最好需要具有时间效应的）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5., 3., 4., ..., 0., 0., 0.],\n",
       "       [4., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       ...,\n",
       "       [5., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 5., 0., ..., 0., 0., 0.]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_item_rating_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       ...,\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.],\n",
       "       [0., 0., 0., ..., 0., 0., 0.]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 初始化相似度矩阵\n",
    "item_sim_array = np.zeros(\n",
    "    shape=(item_quantity,item_quantity)\n",
    ")\n",
    "item_sim_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 记录商品被哪些用户有过打分行为\n",
    "item_rating_users = {}\n",
    "\n",
    "for item_index in range(item_quantity):\n",
    "    item_rating_users[item_index] = np.where(\n",
    "        user_item_rating_array[:,item_index] > 0\n",
    "    )[0].tolist()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对不同的商品1与商品2进行相似度皮尔森计算，并且加入惩罚机制sim = sim * (n / (1 + np.log(1 + n)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0..1..2..3..4..5..6..7..8..9..10..11..12..13..14..15..16..17..18..19..20..21..22..23..24..25..26..27..28..29..30..31..32..33..34..35..36..37..38..39..40..41..42..43..44..45..46..47..48..49..50..51..52..53..54..55..56..57..58..59..60..61..62..63..64..65..66..67..68..69..70..71..72..73..74..75..76..77..78..79..80..81..82..83..84..85..86..87..88..89..90..91..92..93..94..95..96..97..98..99..100..101..102..103..104..105..106..107..108..109..110..111..112..113..114..115..116..117..118..119..120..121..122..123..124..125..126..127..128..129..130..131..132..133..134..135..136..137..138..139..140..141..142..143..144..145..146..147..148..149..150..151..152..153..154..155..156..157..158..159..160..161..162..163..164..165..166..167..168..169..170..171..172..173..174..175..176..177..178..179..180..181..182..183..184..185..186..187..188..189..190..191..192..193..194..195..196..197..198..199..200..201..202..203..204..205..206..207..208..209..210..211..212..213..214..215..216..217..218..219..220..221..222..223..224..225..226..227..228..229..230..231..232..233..234..235..236..237..238..239..240..241..242..243..244..245..246..247..248..249..250..251..252..253..254..255..256..257..258..259..260..261..262..263..264..265..266..267..268..269..270..271..272..273..274..275..276..277..278..279..280..281..282..283..284..285..286..287..288..289..290..291..292..293..294..295..296..297..298..299..300..301..302..303..304..305..306..307..308..309..310..311..312..313..314..315..316..317..318..319..320..321..322..323..324..325..326..327..328..329..330..331..332..333..334..335..336..337..338..339..340..341..342..343..344..345..346..347..348..349..350..351..352..353..354..355..356..357..358..359..360..361..362..363..364..365..366..367..368..369..370..371..372..373..374..375..376..377..378..379..380..381..382..383..384..385..386..387..388..389..390..391..392..393..394..395..396..397..398..399..400..401..402..403..404..405..406..407..408..409..410..411..412..413..414..415..416..417..418..419..420..421..422..423..424..425..426..427..428..429..430..431..432..433..434..435..436..437..438..439..440..441..442..443..444..445..446..447..448..449..450..451..452..453..454..455..456..457..458..459..460..461..462..463..464..465..466..467..468..469..470..471..472..473..474..475..476..477..478..479..480..481..482..483..484..485..486..487..488..489..490..491..492..493..494..495..496..497..498..499..500..501..502..503..504..505..506..507..508..509..510..511..512..513..514..515..516..517..518..519..520..521..522..523..524..525..526..527..528..529..530..531..532..533..534..535..536..537..538..539..540..541..542..543..544..545..546..547..548..549..550..551..552..553..554..555..556..557..558..559..560..561..562..563..564..565..566..567..568..569..570..571..572..573..574..575..576..577..578..579..580..581..582..583..584..585..586..587..588..589..590..591..592..593..594..595..596..597..598..599..600..601..602..603..604..605..606..607..608..609..610..611..612..613..614..615..616..617..618..619..620..621..622..623..624..625..626..627..628..629..630..631..632..633..634..635..636..637..638..639..640..641..642..643..644..645..646..647..648..649..650..651..652..653..654..655..656..657..658..659..660..661..662..663..664..665..666..667..668..669..670..671..672..673..674..675..676..677..678..679..680..681..682..683..684..685..686..687..688..689..690..691..692..693..694..695..696..697..698..699..700..701..702..703..704..705..706..707..708..709..710..711..712..713..714..715..716..717..718..719..720..721..722..723..724..725..726..727..728..729..730..731..732..733..734..735..736..737..738..739..740..741..742..743..744..745..746..747..748..749..750..751..752..753..754..755..756..757..758..759..760..761..762..763..764..765..766..767..768..769..770..771..772..773..774..775..776..777..778..779..780..781..782..783..784..785..786..787..788..789..790..791..792..793..794..795..796..797..798..799..800..801..802..803..804..805..806..807..808..809..810..811..812..813..814..815..816..817..818..819..820..821..822..823..824..825..826..827..828..829..830..831..832..833..834..835..836..837..838..839..840..841..842..843..844..845..846..847..848..849..850..851..852..853..854..855..856..857..858..859..860..861..862..863..864..865..866..867..868..869..870..871..872..873..874..875..876..877..878..879..880..881..882..883..884..885..886..887..888..889..890..891..892..893..894..895..896..897..898..899..900..901..902..903..904..905..906..907..908..909..910..911..912..913..914..915..916..917..918..919..920..921..922..923..924..925..926..927..928..929..930..931..932..933..934..935..936..937..938..939..940..941..942..943..944..945..946..947..948..949..950..951..952..953..954..955..956..957..958..959..960..961..962..963..964..965..966..967..968..969..970..971..972..973..974..975..976..977..978..979..980..981..982..983..984..985..986..987..988..989..990..991..992..993..994..995..996..997..998..999..1000..1001..1002..1003..1004..1005..1006..1007..1008..1009..1010..1011..1012..1013..1014..1015..1016..1017..1018..1019..1020..1021..1022..1023..1024..1025..1026..1027..1028..1029..1030..1031..1032..1033..1034..1035..1036..1037..1038..1039..1040..1041..1042..1043..1044..1045..1046..1047..1048..1049..1050..1051..1052..1053..1054..1055..1056..1057..1058..1059..1060..1061..1062..1063..1064..1065..1066..1067..1068..1069..1070..1071..1072..1073..1074..1075..1076..1077..1078..1079..1080..1081..1082..1083..1084..1085..1086..1087..1088..1089..1090..1091..1092..1093..1094..1095..1096..1097..1098..1099..1100..1101..1102..1103..1104..1105..1106..1107..1108..1109..1110..1111..1112..1113..1114..1115..1116..1117..1118..1119..1120..1121..1122..1123..1124..1125..1126..1127..1128..1129..1130..1131..1132..1133..1134..1135..1136..1137..1138..1139..1140..1141..1142..1143..1144..1145..1146..1147..1148..1149..1150..1151..1152..1153..1154..1155..1156..1157..1158..1159..1160..1161..1162..1163..1164..1165..1166..1167..1168..1169..1170..1171..1172..1173..1174..1175..1176..1177..1178..1179..1180..1181..1182..1183..1184..1185..1186..1187..1188..1189..1190..1191..1192..1193..1194..1195..1196..1197..1198..1199..1200..1201..1202..1203..1204..1205..1206..1207..1208..1209..1210..1211..1212..1213..1214..1215..1216..1217..1218..1219..1220..1221..1222..1223..1224..1225..1226..1227..1228..1229..1230..1231..1232..1233..1234..1235..1236..1237..1238..1239..1240..1241..1242..1243..1244..1245..1246..1247..1248..1249..1250..1251..1252..1253..1254..1255..1256..1257..1258..1259..1260..1261..1262..1263..1264..1265..1266..1267..1268..1269..1270..1271..1272..1273..1274..1275..1276..1277..1278..1279..1280..1281..1282..1283..1284..1285..1286..1287..1288..1289..1290..1291..1292..1293..1294..1295..1296..1297..1298..1299..1300..1301..1302..1303..1304..1305..1306..1307..1308..1309..1310..1311..1312..1313..1314..1315..1316..1317..1318..1319..1320..1321..1322..1323..1324..1325..1326..1327..1328..1329..1330..1331..1332..1333..1334..1335..1336..1337..1338..1339..1340..1341..1342..1343..1344..1345..1346..1347..1348..1349..1350..1351..1352..1353..1354..1355..1356..1357..1358..1359..1360..1361..1362..1363..1364..1365..1366..1367..1368..1369..1370..1371..1372..1373..1374..1375..1376..1377..1378..1379..1380..1381..1382..1383..1384..1385..1386..1387..1388..1389..1390..1391..1392..1393..1394..1395..1396..1397..1398..1399..1400..1401..1402..1403..1404..1405..1406..1407..1408..1409..1410..1411..1412..1413..1414..1415..1416..1417..1418..1419..1420..1421..1422..1423..1424..1425..1426..1427..1428..1429..1430..1431..1432..1433..1434..1435..1436..1437..1438..1439..1440..1441..1442..1443..1444..1445..1446..1447..1448..1449..1450..1451..1452..1453..1454..1455..1456..1457..1458..1459..1460..1461..1462..1463..1464..1465..1466..1467..1468..1469..1470..1471..1472..1473..1474..1475..1476..1477..1478..1479..1480..1481..1482..1483..1484..1485..1486..1487..1488..1489..1490..1491..1492..1493..1494..1495..1496..1497..1498..1499..1500..1501..1502..1503..1504..1505..1506..1507..1508..1509..1510..1511..1512..1513..1514..1515..1516..1517..1518..1519..1520..1521..1522..1523..1524..1525..1526..1527..1528..1529..1530..1531..1532..1533..1534..1535..1536..1537..1538..1539..1540..1541..1542..1543..1544..1545..1546..1547..1548..1549..1550..1551..1552..1553..1554..1555..1556..1557..1558..1559..1560..1561..1562..1563..1564..1565..1566..1567..1568..1569..1570..1571..1572..1573..1574..1575..1576..1577..1578..1579"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..1580..1581..1582..1583..1584..1585..1586..1587..1588..1589..1590..1591..1592..1593..1594..1595..1596..1597..1598..1599..1600..1601..1602..1603..1604..1605..1606..1607..1608..1609..1610..1611..1612..1613..1614..1615..1616..1617..1618..1619..1620..1621..1622..1623..1624..1625..1626..1627..1628..1629..1630..1631..1632..1633..1634..1635..1636..1637..1638..1639..1640..1641..1642..1643..1644..1645..1646..1647..1648..1649.."
     ]
    }
   ],
   "source": [
    "for item_index1 in range(item_quantity):\n",
    "    # 商品1的打分用户\n",
    "    item_index1_rating_users = set(\n",
    "        item_rating_users[item_index1]\n",
    "    )\n",
    "    for item_index2 in range(item_index1 + 1 ,item_quantity):\n",
    "        # 商品2的打分用户\n",
    "        item_index2_rating_users = set(\n",
    "            item_rating_users[item_index2]\n",
    "        )\n",
    "        # 二者的公共打分用户\n",
    "        union_users = list(item_index1_rating_users & item_index2_rating_users)\n",
    "        # 如果有没有公共用户，相似度记为0\n",
    "        if not union_users:\n",
    "            sim = 0\n",
    "        else:\n",
    "            # 公共用户的数目记为n\n",
    "            n = len(union_users)\n",
    "            # 商品1的打分向量\n",
    "            v1 = user_item_rating_array[union_users,item_index1]\n",
    "            # 商品2的打分向量\n",
    "            v2 = user_item_rating_array[union_users,item_index2]\n",
    "            # 计算皮尔森相关系数\n",
    "            sim = 1 - ssd.cosine(v1,v2)\n",
    "            # 如果结果不为数字，记为0\n",
    "            if np.isnan(sim):\n",
    "                sim = 0\n",
    "            else:\n",
    "                # 进行公共用户数据的奖励\n",
    "                sim = sim * (n / (1 + np.log(1 + n)))\n",
    "        # 为相似度矩阵赋值\n",
    "        item_sim_array[item_index1,item_index2] = sim\n",
    "        item_sim_array[item_index2,item_index1] = sim\n",
    "    print(item_index1,end='..') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.  , 13.22, 10.76, ...,  0.  ,  0.59,  0.59],\n",
       "       [13.22,  0.  ,  4.73, ...,  0.  ,  0.59,  0.59],\n",
       "       [10.76,  4.73,  0.  , ...,  0.  ,  0.  ,  0.59],\n",
       "       ...,\n",
       "       [ 0.  ,  0.  ,  0.  , ...,  0.  ,  0.  ,  0.  ],\n",
       "       [ 0.59,  0.59,  0.  , ...,  0.  ,  0.  ,  0.  ],\n",
       "       [ 0.59,  0.59,  0.59, ...,  0.  ,  0.  ,  0.  ]])"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 保留两位小数\n",
    "item_sim_array = np.around(item_sim_array,2)\n",
    "item_sim_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 归一化\n",
    "item_sim_array = item_sim_array / np.array([item_sim_array]).T"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 进行归一化，不同行之间独自，A对B跟B对A不一定是一样的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "item_sim_array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 为用户生成推荐"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 为用户推荐的商品\n",
    "user_recommend = {}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "for user_index in range(user_quantity):\n",
    "    # 用户喜欢的商品索引\n",
    "    user_training_favs = np.where(\n",
    "        user_item_rating_array[user_index] >= 4\n",
    "    )[0].tolist()\n",
    "    # 用户打过分的所有商品索引\n",
    "    user_items_all = np.where(\n",
    "        user_item_rating_array[user_index] > 0\n",
    "    )[0].tolist()\n",
    "    # 第一次的推荐，包括用户已经打过分的商品\n",
    "    recommend_items1 = np.where(\n",
    "        (item_sim_array[user_training_favs] >= 0.8).astype(int).sum(axis=0) > 0\n",
    "    )[0].tolist()\n",
    "    # 第二次的推荐，去掉用户已经打过分的商品\n",
    "    recommend_items2 = list(set(recommend_items1) - set(user_items_all))\n",
    "    user_recommend[user_index] = recommend_items2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 为用户生成推荐，原先用户打过分的需要进行过滤"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 读测试集，评价结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>10</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>12</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>14</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>17</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        1        6       5\n",
       "1        1       10       3\n",
       "2        1       12       5\n",
       "3        1       14       5\n",
       "4        1       17       3"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_test_data = pd.read_csv(\n",
    "    './data/movielen_rating_test.base',\n",
    "    sep='\\t',\n",
    "    names=['user_id','item_id','rating'],\n",
    "    usecols=[0,1,2]\n",
    ")\n",
    "df_test_data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试集矩阵的转换跟训练集的相似"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 20000 entries, 0 to 19999\n",
      "Data columns (total 3 columns):\n",
      "user_id    20000 non-null int64\n",
      "item_id    20000 non-null int64\n",
      "rating     20000 non-null int64\n",
      "dtypes: int64(3)\n",
      "memory usage: 468.8 KB\n"
     ]
    }
   ],
   "source": [
    "df_test_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>745.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>135.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>269.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>136.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>538.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        0    745.0       5\n",
       "1        0    135.0       3\n",
       "2        0    269.0       5\n",
       "3        0    136.0       5\n",
       "4        0    538.0       3"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 把测试集中的id变更为index，如果测试集中有训练集中为出现的用户或商品，记为None，也就是Nan\n",
    "\n",
    "def deal_with_user_id(user_id):\n",
    "    if user_id in user_id_to_index_dict.keys():\n",
    "        return user_id_to_index_dict[user_id]\n",
    "    else:\n",
    "        return None\n",
    "\n",
    "def deal_with_item_id(item_id):\n",
    "    if item_id in item_id_to_index_dict.keys():\n",
    "        return item_id_to_index_dict[item_id]\n",
    "    else:\n",
    "        return None\n",
    "    \n",
    "df_test_data['user_id'] = df_test_data['user_id'].apply(\n",
    "    deal_with_user_id\n",
    ")\n",
    "\n",
    "df_test_data['item_id'] = df_test_data['item_id'].apply(\n",
    "     deal_with_item_id\n",
    ")\n",
    "df_test_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 20000 entries, 0 to 19999\n",
      "Data columns (total 3 columns):\n",
      "user_id    20000 non-null int64\n",
      "item_id    19968 non-null float64\n",
      "rating     20000 non-null int64\n",
      "dtypes: float64(1), int64(2)\n",
      "memory usage: 468.8 KB\n"
     ]
    }
   ],
   "source": [
    "df_test_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>745.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>135.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>269.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>136.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>538.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0</td>\n",
       "      <td>1029.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>0</td>\n",
       "      <td>324.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>0</td>\n",
       "      <td>503.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>0</td>\n",
       "      <td>325.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>0</td>\n",
       "      <td>326.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>0</td>\n",
       "      <td>474.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>0</td>\n",
       "      <td>1333.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>0</td>\n",
       "      <td>327.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>0</td>\n",
       "      <td>935.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>0</td>\n",
       "      <td>270.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>0</td>\n",
       "      <td>539.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>0</td>\n",
       "      <td>328.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>0</td>\n",
       "      <td>540.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>0</td>\n",
       "      <td>504.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>0</td>\n",
       "      <td>329.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>0</td>\n",
       "      <td>475.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>0</td>\n",
       "      <td>746.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>22</th>\n",
       "      <td>0</td>\n",
       "      <td>330.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23</th>\n",
       "      <td>0</td>\n",
       "      <td>271.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24</th>\n",
       "      <td>0</td>\n",
       "      <td>747.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25</th>\n",
       "      <td>0</td>\n",
       "      <td>541.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26</th>\n",
       "      <td>0</td>\n",
       "      <td>331.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27</th>\n",
       "      <td>0</td>\n",
       "      <td>200.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>28</th>\n",
       "      <td>0</td>\n",
       "      <td>748.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>29</th>\n",
       "      <td>0</td>\n",
       "      <td>332.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19970</th>\n",
       "      <td>453</td>\n",
       "      <td>751.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19971</th>\n",
       "      <td>453</td>\n",
       "      <td>485.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19972</th>\n",
       "      <td>453</td>\n",
       "      <td>372.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19973</th>\n",
       "      <td>453</td>\n",
       "      <td>296.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19974</th>\n",
       "      <td>453</td>\n",
       "      <td>757.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19975</th>\n",
       "      <td>453</td>\n",
       "      <td>892.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19976</th>\n",
       "      <td>453</td>\n",
       "      <td>1174.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19977</th>\n",
       "      <td>454</td>\n",
       "      <td>70.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19978</th>\n",
       "      <td>454</td>\n",
       "      <td>148.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19979</th>\n",
       "      <td>454</td>\n",
       "      <td>157.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19980</th>\n",
       "      <td>454</td>\n",
       "      <td>435.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19981</th>\n",
       "      <td>454</td>\n",
       "      <td>872.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19982</th>\n",
       "      <td>455</td>\n",
       "      <td>345.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19983</th>\n",
       "      <td>455</td>\n",
       "      <td>158.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19984</th>\n",
       "      <td>455</td>\n",
       "      <td>519.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19985</th>\n",
       "      <td>455</td>\n",
       "      <td>739.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19986</th>\n",
       "      <td>456</td>\n",
       "      <td>97.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19987</th>\n",
       "      <td>456</td>\n",
       "      <td>100.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19988</th>\n",
       "      <td>456</td>\n",
       "      <td>218.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19989</th>\n",
       "      <td>456</td>\n",
       "      <td>259.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19990</th>\n",
       "      <td>456</td>\n",
       "      <td>589.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19991</th>\n",
       "      <td>456</td>\n",
       "      <td>759.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19992</th>\n",
       "      <td>456</td>\n",
       "      <td>501.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19993</th>\n",
       "      <td>456</td>\n",
       "      <td>628.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19994</th>\n",
       "      <td>457</td>\n",
       "      <td>77.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19995</th>\n",
       "      <td>457</td>\n",
       "      <td>1015.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19996</th>\n",
       "      <td>457</td>\n",
       "      <td>933.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19997</th>\n",
       "      <td>458</td>\n",
       "      <td>729.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19998</th>\n",
       "      <td>459</td>\n",
       "      <td>135.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19999</th>\n",
       "      <td>461</td>\n",
       "      <td>462.0</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>19968 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "       user_id  item_id  rating\n",
       "0            0    745.0       5\n",
       "1            0    135.0       3\n",
       "2            0    269.0       5\n",
       "3            0    136.0       5\n",
       "4            0    538.0       3\n",
       "5            0   1029.0       4\n",
       "6            0    324.0       4\n",
       "7            0    503.0       3\n",
       "8            0    325.0       2\n",
       "9            0    326.0       3\n",
       "10           0    474.0       4\n",
       "11           0   1333.0       2\n",
       "12           0    327.0       4\n",
       "13           0    935.0       5\n",
       "14           0    270.0       4\n",
       "15           0    539.0       3\n",
       "16           0    328.0       4\n",
       "17           0    540.0       3\n",
       "18           0    504.0       3\n",
       "19           0    329.0       4\n",
       "20           0    475.0       5\n",
       "21           0    746.0       4\n",
       "22           0    330.0       3\n",
       "23           0    271.0       5\n",
       "24           0    747.0       4\n",
       "25           0    541.0       3\n",
       "26           0    331.0       3\n",
       "27           0    200.0       3\n",
       "28           0    748.0       4\n",
       "29           0    332.0       3\n",
       "...        ...      ...     ...\n",
       "19970      453    751.0       3\n",
       "19971      453    485.0       3\n",
       "19972      453    372.0       4\n",
       "19973      453    296.0       2\n",
       "19974      453    757.0       2\n",
       "19975      453    892.0       4\n",
       "19976      453   1174.0       2\n",
       "19977      454     70.0       5\n",
       "19978      454    148.0       3\n",
       "19979      454    157.0       4\n",
       "19980      454    435.0       3\n",
       "19981      454    872.0       3\n",
       "19982      455    345.0       3\n",
       "19983      455    158.0       1\n",
       "19984      455    519.0       3\n",
       "19985      455    739.0       4\n",
       "19986      456     97.0       4\n",
       "19987      456    100.0       5\n",
       "19988      456    218.0       4\n",
       "19989      456    259.0       4\n",
       "19990      456    589.0       4\n",
       "19991      456    759.0       4\n",
       "19992      456    501.0       4\n",
       "19993      456    628.0       3\n",
       "19994      457     77.0       4\n",
       "19995      457   1015.0       4\n",
       "19996      457    933.0       4\n",
       "19997      458    729.0       3\n",
       "19998      459    135.0       3\n",
       "19999      461    462.0       5\n",
       "\n",
       "[19968 rows x 3 columns]"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 删除掉为Nan的数据\n",
    "df_test_data = df_test_data.dropna()\n",
    "df_test_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>745</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>135</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>269</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>136</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>538</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        0      745       5\n",
       "1        0      135       3\n",
       "2        0      269       5\n",
       "3        0      136       5\n",
       "4        0      538       3"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变更item_id的类型为int\n",
    "df_test_data['item_id'] = df_test_data['item_id'].astype(int)\n",
    "df_test_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_index</th>\n",
       "      <th>item_index</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>745</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0</td>\n",
       "      <td>135</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0</td>\n",
       "      <td>269</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0</td>\n",
       "      <td>136</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0</td>\n",
       "      <td>538</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_index  item_index  rating\n",
       "0           0         745       5\n",
       "1           0         135       3\n",
       "2           0         269       5\n",
       "3           0         136       5\n",
       "4           0         538       3"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 变更列名\n",
    "df_test_data.columns = ['user_index','item_index','rating']\n",
    "df_test_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 19968 entries, 0 to 19999\n",
      "Data columns (total 3 columns):\n",
      "user_index    19968 non-null int64\n",
      "item_index    19968 non-null int32\n",
      "rating        19968 non-null int64\n",
      "dtypes: int32(1), int64(2)\n",
      "memory usage: 546.0 KB\n"
     ]
    }
   ],
   "source": [
    "df_test_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取用户打分超过4分的物品为用户喜欢的物品\n",
    "user_fav = {}\n",
    "for user_index,groupby_userindex in df_test_data.groupby('user_index'):\n",
    "    items_rating = groupby_userindex.groupby('item_index')['rating'].mean()\n",
    "    user_fav[user_index] = items_rating[items_rating >= 4].index.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "准确率 0.015624217118997911\n",
      "召回率 0.9999109290104213\n"
     ]
    }
   ],
   "source": [
    "recommend_quantity = 0\n",
    "fav_quantity = 0\n",
    "union_quantity = 0\n",
    "\n",
    "for user_index in user_recommend.keys():\n",
    "    if user_index in user_fav.keys():\n",
    "        recommend_quantity += len(user_recommend[user_index])\n",
    "        fav_quantity += len(user_fav[user_index])\n",
    "        union_quantity += len(\n",
    "            set(user_recommend[user_index]) & set(user_fav[user_index])\n",
    "        )\n",
    "\n",
    "print('准确率',union_quantity / recommend_quantity)\n",
    "print('召回率',union_quantity / fav_quantity)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
